﻿using FlyingEye.ApplicationContracts;
using FlyingEye.ApplicationContracts.SignalRHubs;
using FlyingEye.SignalRHubs;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Logging;
using System.Data.Common;
using System.Net.Http;
using WpfApp.Exceptions;

namespace FlyingEyeClient.ApplicationServices.SignalRHubs
{
    public class SignalRClientService
    {
        private HubConnection? _connection;

        public HubConnection Connection
        {
            get
            {
                if (_connection == null || _connection.State != HubConnectionState.Connected)
                {
                    throw new InvalidOperationException("未连接 Hub 服务器！");
                }

                return _connection;
            }
        }

        private readonly ILogger _log;

        public bool IsConnected => _connection?.State == HubConnectionState.Connected;

        public string ClientId { get; private set; } = string.Empty;

        public SignalRClientService(ILogger<SignalRClientService> log)
        {
            _log = log;
        }

        /// <summary>
        /// 连接事务回调
        /// </summary>
        public event EventHandler<ConnectionEventArgs>? Connect;

        public event EventHandler<ClassifyMeterialMessage>? ClassifyMeterial;

        public bool IsWindows7()
        {
            var os = Environment.OSVersion;
            // Windows 7 的版本号为 6.1.7601
            return os.Platform == PlatformID.Win32NT
                   && os.Version.Major == 6
                   && os.Version.Minor == 1;
        }

        /// <summary>
        /// 连接 Hub 服务器
        /// </summary>
        /// <exception cref="InvalidOperationException">注册节点失败异常</exception>
        public async Task ConnectAsync(string host, string clientId)
        {
            this.ClientId = clientId;
            _connection = new HubConnectionBuilder()
            .WithUrl(new Uri($"https://{host}/DeviceClientHub"), options =>
            {
                if (IsWindows7())
                {
                    options.HttpMessageHandlerFactory = handle => new HttpClientHandler()
                    {
                        ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true,
                    };
                }
            })
            .WithAutomaticReconnect(new SignalRRetryPolicy())
            .Build();

            try
            {
                // 连接到 HUB 中心
                await _connection.StartAsync();
            }
            catch (Exception ex)
            {
                _log.LogError(ex, "连接 Hub 中心失败");
                // 这里是连接失败，释放资源即可
                await _connection.DisposeAsync();
                _connection = null;
                throw new UserFriendlyException("连接 Hub 中心失败");
            }

            // 添加客户端映射
            await _connection.InvokeAsync("AddClientMappingAsync", new ClientMappingMessage() { DeviceId = this.ClientId });

            _connection.Reconnecting += OnReconnecting;
            _connection.Reconnected += OnReconnected;

            // 注册方法
            RegisterMethods(_connection);
            this.Connect?.Invoke(this, new ConnectionEventArgs(SignalRConnectionStatus.Connected));
        }

        private Task OnReconnecting(Exception? arg)
        {
            this.Connect?.Invoke(this, new ConnectionEventArgs(SignalRConnectionStatus.Reconnecting));
            return Task.CompletedTask;
        }

        private async Task OnReconnected(string? arg)
        {
            // 重新连接完成之后，重新注册客户端
            if (_connection != null)
                // 添加客户端映射
                await _connection.InvokeAsync("AddClientMappingAsync", new ClientMappingMessage() { DeviceId = this.ClientId });

            this.Connect?.Invoke(this, new ConnectionEventArgs(SignalRConnectionStatus.Reconnected));
        }

        /// <summary>
        /// 注册 API 方法，然后我们可以从服务器调用这些方法
        /// </summary>
        private void RegisterMethods(HubConnection hubConnection)
        {
            hubConnection.On<ClassifyMeterialMessage>("ExecuteClassifyMeterialAsync", message =>
            {
                ClassifyMeterial?.Invoke(this, message);
            });
        }

        /// <summary>
        /// 断开连接。
        /// </summary>
        public async Task DisconnectAsync()
        {
            // 关闭 SignalR 连接
            if (_connection != null)
            {
                await _connection.StopAsync();
                _connection = null;
                this.Connect?.Invoke(this, new ConnectionEventArgs(SignalRConnectionStatus.Disconnected));
            }
        }
    }
}
